/************************ (C) COPYLEFT 2018 Merafour *************************

* File Name          : cledMatrix.c
* Author             : Merafour
* Last Modified Date : 01/10/2019
* Description        : cled Matrix.
********************************************************************************
* https://merafour.blog.163.com
* merafour@163.com
* https://github.com/merafour
******************************************************************************/
#include "crgbMatrix.h"
#include <string.h>

#define  mLED_SIZE   (LEDMatrixWidth*LEDMatrixHeight)
//static struct BRGB mLED[LEDMatrixWidth * LEDMatrixHeight+1]; // Will always be at least 1
//static uint32_t mLED[LEDMatrixWidth * LEDMatrixHeight+1]; // Will always be at least 1
static volatile uint32_t mLED[mLED_SIZE+1]; // Will always be at least 1
static inline uint16_t mXY(int16_t x, int16_t y)
{
	// Beware, this returns a special out of bounds value, you need an extra
	// safety pixel at the end of your array to host this, or if you use
	// drawPixel, the value willl get rejected.
	// 安全检查
	if((x < 0) || (y < 0) || (x >= LEDMatrixWidth) || (y >= LEDMatrixHeight)) return mLED_SIZE; //return (LEDMatrixWidth*LEDMatrixHeight/*-1*/);
#ifdef MATRIX_SCAN_XINV   // 反向扫描
	x = (LEDMatrixWidth - 1) - x;
#endif
#ifdef MATRIX_SCAN_YINV   // 反向扫描
	y = (LEDMatrixHeight - 1) - y;
#endif

#ifndef  MATRIX_TYPE
#error   "Please define MATRIX_TYPE"
#elif (HORIZONTAL_MATRIX==MATRIX_TYPE)
	//return((y * LEDMatrixWidth) + x);
	return(MultipLEDMatrixWidth(y) + x);
#elif (VERTICAL_MATRIX==MATRIX_TYPE)
	//return((x * LEDMatrixHeight) + y);
	return(MultipLEDMatrixHeight(x) + y);
#elif (HORIZONTAL_ZIGZAG_MATRIX==MATRIX_TYPE)
	if (y % 2)
	{
		return((((y + 1) * LEDMatrixWidth) - 1) - x);
	}
	else
	{
		return((y * LEDMatrixWidth) + x);
	}
#elif (VERTICAL_ZIGZAG_MATRIX==MATRIX_TYPE)
	if (x % 2)
	{
		return((((x + 1) * LEDMatrixHeight) - 1) - y);
	}
	else
	{
		return((x * LEDMatrixHeight) + y);
	}
#else
#error   "Please check MATRIX_TYPE"
#endif
}
//static inline uint16_t mXYZ(int16_t x, int16_t y, int16_t z)
//{
//	// Beware, this returns a special out of bounds value, you need an extra
//	// safety pixel at the end of your array to host this, or if you use
//	// drawPixel, the value willl get rejected.
//	// 安全检查
//	if((x < 0) || (y < 0) || (z < 0) || (x >= (LEDMatrixWidth/LEDMatrixZAxis)) || (y >= LEDMatrixHeight) || (z >= LEDMatrixZAxis)) return mLED_SIZE; //return (LEDMatrixWidth*LEDMatrixHeight/*-1*/);
//#ifdef MATRIX_SCAN_XINV   // 反向扫描
//	x = ((LEDMatrixWidth/LEDMatrixZAxis) - 1) - x;
//#endif
//#ifdef MATRIX_SCAN_YINV   // 反向扫描
//	y = (LEDMatrixHeight - 1) - y;
//#endif

//#ifndef  MATRIX_TYPE
//#error   "Please define MATRIX_TYPE"
//#elif (HORIZONTAL_MATRIX==MATRIX_TYPE)
//	//return((y * LEDMatrixWidth) + x);
//	//return(MultipLEDMatrixWidth(y) + x);
//	return MultipLEDMatrixPos(x,y,z);
//#elif (VERTICAL_MATRIX==MATRIX_TYPE)
//	//return((x * LEDMatrixHeight) + y);
//	return(MultipLEDMatrixHeight(x) + y);
//#elif (HORIZONTAL_ZIGZAG_MATRIX==MATRIX_TYPE)
//	if (y % 2)
//	{
//		return((((y + 1) * LEDMatrixWidth) - 1) - x);
//	}
//	else
//	{
//		return((y * LEDMatrixWidth) + x);
//	}
//#elif (VERTICAL_ZIGZAG_MATRIX==MATRIX_TYPE)
//	if (x % 2)
//	{
//		return((((x + 1) * LEDMatrixHeight) - 1) - y);
//	}
//	else
//	{
//		return((x * LEDMatrixHeight) + y);
//	}
//#else
//#error   "Please check MATRIX_TYPE"
//#endif
//}

// It's good to implement those, even if using transaction API
// (x,y) is topmost point; if unsure, calling function
// should sort endpoints or call drawLine() instead
void mled_drawFastVLine(const int16_t x, const int16_t y, const uint16_t h, const uint32_t color)
{
	// writeLine(x, y, x, y+h-1, color);
    for (int16_t i=y; i<y+h; i++) 
	{
        mled_draw_pixel(x, i, color);
    }
}

// (x,y) is leftmost point; if unsure, calling function
// should sort endpoints or call drawLine() instead
void mled_drawFastHLine(const int16_t x, const int16_t y, const uint16_t w, const uint32_t color)
{
	// writeLine(x, y, x+w-1, y, color);
    for (int16_t i=x; i<x+w; i++) 
	{
        mled_draw_pixel(i, y, color);
    }
}
// 
void mled_fill_rect(const int16_t x, const int16_t y, const uint16_t w, const uint16_t h, const uint32_t color)
{
    for (int16_t i=x; i<x+w; i++) 
	{
        mled_drawFastVLine(i, y, h, color);
    }
}

/*void mled_fillScreen(const uint32_t color)
{
    // Update in subclasses if desired!
    mled_fill_rect(0, 0, LEDMatrixWidth, LEDMatrixHeight, color);
}*/
// 描点
void mled_draw_pixel(const int16_t x, const int16_t y, const uint32_t color) 
{
	//if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
	//mLED[mXY(x,y)].color = color;
	//mLED[mXY(x,y)] = color;
    uint16_t pos = mXY(x,y);
	mLED[pos] = color;
}
//void mega_draw_pixel(const int16_t x, const int16_t y, const int16_t z, const uint32_t color) 
//{
//	//if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
//	//mLED[mXY(x,y)].color = color;
//	//mLED[mXY(x,y)] = color;
//	uint16_t pos = mXYZ(x,y,z);
//	mLED[pos] = color;
//}
/*void mled_draw_index(const uint16_t index, const uint32_t color) 
{
	//if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
	if(index<mLED_SIZE) mLED[index] = color;
}*/
/*void mled_buffer(const uint8_t data[], const uint16_t size) 
{
	//if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
	if(size<(mLED_SIZE<<2)) memcpy(mLED, data, size);
}*/
// 获取像素点数据
uint32_t mled_get_pixel(const int16_t x, const int16_t y) 
{
	//if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
	//return mLED[mXY(x,y)].color;
	// 安全检查
	if((x < 0) || (y < 0) || (x >= LEDMatrixWidth) || (y >= LEDMatrixHeight)) return 0x00000000; //return (LEDMatrixWidth*LEDMatrixHeight/*-1*/);
    return mLED[mXY(x,y)];
}
// 获取帧缓存
//const struct BRGB* mled_get_frame_buffer(void) { return mLED; }
const uint32_t* mled_get_frame_buffer(void) { return mLED; }

// Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y)
// position.  For 16-bit display devices; no color reduction performed.
//void mled_draw_RGB565_Bitmap(const int16_t x, const int16_t y, const uint16_t bitmap[], const int16_t w, const int16_t h) 
//{
//    for(int16_t j=0; j<h; j++/*, y++*/) 
//	{
//        for(int16_t i=0; i<w; i++ ) 
//		{
//            //writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
//			mled_draw_pixel(x+i, y+j, mled_rgb_16to24(bitmap[j * w + i]));
//        }
//    }
//}
//void mled_draw_RGB888_Bitmap(const int16_t x, const int16_t y, const uint32_t bitmap[], const int16_t w, const int16_t h) 
//{
//    for(int16_t j=0; j<h; j++/*, y++*/) 
//	{
//        for(int16_t i=0; i<w; i++ ) 
//		{
//            //writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
//			mled_draw_pixel(x+i, y+j, bitmap[j * w + i]);
//        }
//    }
//}
//void mled_kb_draw_RGB565_Bitmap(const int16_t x, const int16_t y, const uint16_t bitmap[], const int16_t w, const int16_t h) 
//{
//    for(int16_t j=0; j<h; j++/*, y++*/) 
//	{
//        for(int16_t i=0; i<w; i++ ) 
//		{
//            //writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
//			mled_kb_draw_pixel(x+i, y+j, mled_rgb_16to24(bitmap[j * w + i]));
//        }
//    }
//}
//void mled_kb_draw_RGB888_Bitmap(const int16_t x, const int16_t y, const uint32_t bitmap[], const int16_t width, const int16_t height) 
//{
//    for(int16_t j=0; j<height; j++/*, y++*/) 
//	{
//        for(int16_t i=0; i<width; i++ ) 
//		{
//            //writePixel(x+i, y, pgm_read_word(&bitmap[j * w + i]));
//			mled_draw_pixel(x+i, y+j, bitmap[pmXY(i, j, width, height)]);
//        }
//    }
//}

//void mled_kb_mRight_draw_RGB888_Bitmap(const int16_t x, const int16_t y, const uint32_t bitmap[], const uint16_t width, const uint16_t height, const uint8_t dpi, const uint8_t grade)
//{
//	uint32_t mColor, nColor, pColor;
//	//uint16_t mPixel, nPixel, pPixel;
//	//qDebug("\r\n\r\n[%s--%d] bitmap[0]:0x%08X alpha:%d \r\n", __func__, __LINE__, bitmap[0], mled_rgb_alpha(100, 10, 10, 1));
//    for(int16_t j=0; j<height; j++/*, y++*/) 
//	{
//        for(int16_t i=width; i>=0; i-- )//for(int16_t i=0; i<width; i++ ) 
//		{
//			//pPixel = pmXY(i, j, width, height);
//			//if(i<width) mled_kb_draw_pixel(x+i, y+j, bitmap[pmXY(i, j, width, height)]);
//			// 右移,颜色过渡
//			//mColor = mled_kb_get_pixel(x+i, y+j);   // 当前像素点
//			//nColor = mled_kb_get_pixel(x+i-1, y+j); // 下一个像素点,过渡
//			mColor = 0; nColor = 0;
//			if(i<width) mColor = bitmap[pmXY(i, j, width, height)];
//			if(i>0) nColor = bitmap[pmXY(i-1, j, width, height)];
//			// 混色
//			//pColor = ((255-grade)*mColor+nColor*grade)/dpi;
//			pColor = mled_rgb_alpha(mColor, nColor, dpi, dpi-grade);
//			//qDebug("[%s--%d] (%d,%d) mColor:0x%08X nColor:0x%08X pColor:0x%08X\r\n", __func__, __LINE__, i, j, mColor, nColor, pColor);
//			mled_kb_draw_pixel(x+i, y+j, pColor);
//        }
//    }
//}

